using System;
using System.Text;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace MBR3Driver
{
    public class MBR3Kit : I2CHelper
    {
        /* CY8CMBR3116 Register Map Offset Address */
        const int REGMAP_ORIGIN = 0x00;
        const int SENSOR_PATTERN = 0x00;
        const int FSS_EN = 0x02;
        const int TOGGLE_EN = 0x04;
        const int LED_ON_EN = 0x06;
        const int SENSITIVITY0 = 0x08;
        const int SENSITIVITY1 = 0x09;
        const int SENSITIVITY2 = 0x0A;
        const int SENSITIVITY3 = 0x0B;
        const int BASE_THRESHOLD0 = 0x0C;
        const int BASE_THRESHOLD1 = 0x0D;
        const int FINGER_THRESHOLD2 = 0x0E;
        const int FINGER_THRESHOLD3 = 0x0F;
        const int FINGER_THRESHOLD4 = 0x10;
        const int FINGER_THRESHOLD5 = 0x11;
        const int FINGER_THRESHOLD6 = 0x12;
        const int FINGER_THRESHOLD7 = 0x13;
        const int FINGER_THRESHOLD8 = 0x14;
        const int FINGER_THRESHOLD9 = 0x15;
        const int FINGER_THRESHOLD10 = 0x16;
        const int FINGER_THRESHOLD11 = 0x17;
        const int FINGER_THRESHOLD12 = 0x18;
        const int FINGER_THRESHOLD13 = 0x19;
        const int FINGER_THRESHOLD14 = 0x1A;
        const int FINGER_THRESHOLD15 = 0x1B;
        const int SENSOR_DEBOUNCE = 0x1C;
        const int BUTTON_HYS = 0x1D;
        const int BUTTON_BUT = 0x1E;
        const int BUTTON_LBR = 0x1F;
        const int BUTTON_NNT = 0x20;
        const int BUTTON_NT = 0x21;
        const int PROX_EN = 0x26;
        const int PROX_CFG = 0x27;
        const int PROX_CFG2 = 0x28;
        const int PROX_TOUCH_TH0 = 0x2A;
        const int PROX_TOUCH_TH1 = 0x2C;
        const int PROX_HYS = 0x30;
        const int PROX_BUT = 0x31;
        const int PROX_LBR = 0x32;
        const int PROX_NNT = 0x33;
        const int PROX_NT = 0x34;
        const int PROX_POSITIVE_TH0 = 0x35;
        const int PROX_POSITIVE_TH1 = 0x36;
        const int PROX_NEGATIVE_TH0 = 0x39;
        const int PROX_NEGATIVE_TH1 = 0x3A;
        const int LED_ON_TIME = 0x3D;
        const int BUZZER_CFG = 0x3E;
        const int BUZZER_ON_TIME = 0x3F;
        const int GPO_CFG = 0x40;
        const int PWM_DUTYCYCLE_CFG0 = 0x41;
        const int PWM_DUTYCYCLE_CFG1 = 0x42;
        const int PWM_DUTYCYCLE_CFG2 = 0x43;
        const int PWM_DUTYCYCLE_CFG3 = 0x44;
        const int PWM_DUTYCYCLE_CFG4 = 0x45;
        const int PWM_DUTYCYCLE_CFG5 = 0x46;
        const int PWM_DUTYCYCLE_CFG6 = 0x47;
        const int PWM_DUTYCYCLE_CFG7 = 0x48;
        const int SPO_CFG = 0x4C;
        const int DEVICE_CFG0 = 0x4D;
        const int DEVICE_CFG1 = 0x4E;
        const int DEVICE_CFG2 = 0x4F;
        const int I2C_ADDR = 0x51;
        const int REFRESH_CTRL = 0x52;
        const int STATE_TIMEOUT = 0x55;
        const int SLIDER_CFG = 0x5D;
        const int SLIDER1_CFG = 0x61;
        const int SLIDER1_RESOLUTION = 0x62;
        const int SLIDER1_THRESHOLD = 0x63;
        const int SLIDER2_CFG = 0x67;
        const int SLIDER2_RESOLUTION = 0x68;
        const int SLIDER2_THRESHOLD = 0x69;
        const int SLIDER_DEBOUNCE = 0x6F;
        const int SLIDER_BUT = 0x70;
        const int SLIDER_LBR = 0x71;
        const int SLIDER_NNT = 0x72;
        const int SLIDER_NT = 0x73;
        const int CONFIG_CRC = 0x7E;
        const int GPO_OUTPUT_STATE = 0x80;
        const int SENSOR_ID = 0x82;
        const int CTRL_CMD = 0x86;
        const int BUTTON_STATUS = 0xAA;
        const int PROX_STAT = 0xAE;

        /* Command Codes */
        const int CMD_NULL = 0x00;
        const int SAVE_CHECK_CRC = 0x02;
        const int CALC_CRC = 0x03;
        const int LOAD_FACTORY = 0x04;
        const int LOAD_PRIMARY = 0x05;
        const int LOAD_SECONDARY = 0x06;
        const int SLEEP = 0x07;
        const int CLEAR_LATCHED_STATUS = 0x08;
        const int CMD_RESET_PROX0_FILTER = 0x09;
        const int CMD_RESET_PROX1_FILTER = 0x0A;
        const int ENTER_CONFIG_MODE = 0x0B;
        const int EXIT_CONTROL_RUN = 0xFE;
        const int SW_RESET = 0xFF;

        /* Total number of configuration registers */
        const int TOTAL_CONFIG_REG_COUNT = 0x80;

        /* Length of Register Map */
        const int REG_MAP_LEN = 256;

        /* Slave Address (Default) */
        const int SLAVE_ADDR = 0x37;

        const int NO_OF_KIT_BUTTONS = 4;

        const int BUZ_ON_1_33kHz = 0x85;
        const int BUZ_OFF_1_33kHz = 0x05;
        const int SPO_ENABLE = 0x03;
        const int SPO_DISABLE = 0x00;

        private InterruptPort input;
        private int ButtonClicked = 0;

        const int clockRateKhz = 100;

        public event ClickHandler OnClick;
        public event ClickHandler OnRelease;

        public delegate void ClickHandler(MBR3Kit sender, ClickArgs e);

        public MBR3Kit(Cpu.Pin InterruptPin) : this(InterruptPin, SLAVE_ADDR)
        {
        }

        public MBR3Kit(Cpu.Pin InterruptPin, byte MBR3Address) : base(MBR3Address, clockRateKhz)
        {
            configureMBR3();

            input = new InterruptPort(InterruptPin, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow);
            input.OnInterrupt += HostInterruptISR;
        }

        public void Start()
        {
            Debug.Print(" Touch any of the Buttons (BTN1,BTN2,BTN3 BTN4) \n");
            input.EnableInterrupt();
        }

        public void Stop()
        {
            Debug.Print(" MBR3 stopped \n");
            input.DisableInterrupt();
        }

        private void HostInterruptISR(uint port, uint state, DateTime time)
        {
            byte[] c = new byte[3];
            ClickArgs args = new ClickArgs();

            ReadFromRegister(BUTTON_STATUS, c);

            if (ButtonClicked > 0)
            {
                args.ButtonValue = ButtonClicked.ToString();
                args.ButtonClicked = (CapButton)ButtonClicked;
                ButtonClicked = 0;

                OnReleaseEvent(args);
            }

            ButtonClicked = c[0];
            args.ButtonClicked = (CapButton)ButtonClicked;
            args.ButtonValue = ButtonClicked.ToString();

            OnClickEvent(args);

            input.ClearInterrupt();
        }

        private void OnClickEvent(ClickArgs e)
        {
            if (OnClick != null)
            {
                OnClick(this, e);
            }
        }

        private void OnReleaseEvent(ClickArgs e)
        {
            if (OnRelease != null)
            {
                OnRelease(this, e);
            }
        }

        public void configureMBR3()
        {
            //Paste/Initialize the configuration array copied from the IIC file of Ez-Click here under the configData array  
            //Buzzer and Host Int Enabled: Jumper J15 in Configuration A on CY3280-MBR3 Kit
            //byte[] configData = {   0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x80,
            //                        0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
            //                        0x7F, 0x7F, 0x7F, 0x7F, 0x03, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
            //                        0x05, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01,
            //                        0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F,
            //                        0xFF, 0x00, 0x00, 0x00, 0x43, 0x03, 0x01, 0x58,
            //                        0x00, 0x37, 0x06, 0x00, 0x00, 0x0A, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            //                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x26 };

            byte[] configData = {     0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x80,
    0x80, 0x80, 0x80, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
    0x7F, 0x7F, 0x7F, 0x7F, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    0x05, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x01,
    0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0x00, 0x00, 0x00, 0x43, 0x03, 0x01, 0x58,
    0x00, 0x37, 0x06, 0x00, 0x00, 0x0A, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x1E };

            configureMBR3(configData);
        }

        public void configureMBR3(byte[] configData)
        {
            this.WriteToRegister(REGMAP_ORIGIN, 0x00);
            this.WriteToRegister(REGMAP_ORIGIN, 0x00);

            this.WriteToRegister(REGMAP_ORIGIN, configData);
            this.WriteToRegister(CTRL_CMD, SAVE_CHECK_CRC);
            this.WriteToRegister(CTRL_CMD, SW_RESET);
        }
    }

    public class ClickArgs : EventArgs
    {
        public CapButton ButtonClicked;
        public string ButtonValue;
    }

    public enum CapButton
    {
        BTN1 = 0x08, BTN2 = 0x10, BTN3 = 0x20, BTN4 = 0x40
    }
}
